package com.sptus.system.domain.alarm;

import com.sptus.common.core.redis.RedisCache;
import com.sptus.common.utils.StringUtils;
import com.sptus.system.domain.Equipment;
import com.sptus.system.service.IConfigInfoService;
import com.sptus.system.service.ISptDevLogService;
import com.sptus.system.service.impl.WorkOrdersServiceImpl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class AlarmParser {
    private static final int BITS_PER_WORD = 32;
    private static final ConcurrentHashMap<Integer, List<Alarm>> ALARM_CACHE = new ConcurrentHashMap<>();

    /**
     * 告警枚举类
     */
    public enum AlarmEnum {
        // 基础告警 (0-31)
        LINE_LOSS(0, "Line Loss", 2, 1, 240),
        SOLAR1_LOSS(1, "Solar1 Loss", 1, 576, 6),
        SOLAR2_LOSS(2, "Solar2 Loss", 1, 576, 6),
        SOLAR3_LOSS(3, "Solar3 Loss", 1, 576, 6),
        SOLAR4_LOSS(4, "Solar4 Loss", 1, 576, 6),
        BATTERY_LOSS(5, "Battery Loss(Battery Open)", 3, 288, 6),
        OPV_SHORT(6, "OPVShort", 1, 0, 0),
        OVER_TEMPERATURE(7, "Over temperature", 3, 288, 6),
        FAN_LOCKED(8, "Fan locked", 1, 48, 6),
        BATTERY_UNDER_SHUTDOWN(9, "Battery under shutdown", 2, 1, 240),
        BATTERY_DERATING(10, "Battery derating", 2, 0, 0),
        OVERLOAD(11, "Overload", 1, 1, 240),
        EEPROM_FAULT(12, "Eeprom fault", 1, 1, 240),
        POWER_LIMIT(13, "Power limit", 1, 0, 0),
        PV_VOLTAGE_HIGH(14, "PV voltage high", 2, 576, 6),
        MPPT_OVERLOAD_WARNING(15, "MPPT overload warning", 2, 0, 0),
        BATTERY_TOO_LOW(16, "Battery too low to charge", 3, 0, 0),
        PV_VOLTAGE_OVER_1(17, "PV Voltage Over 1", 1, 576, 6),
        PV_VOLTAGE_OVER_2(18, "PV Voltage Over 2", 1, 576, 6),
        PV_VOLTAGE_OVER_3(19, "PV Voltage Over 3", 1, 576, 6),
        PV_VOLTAGE_OVER_4(20, "PV Voltage Over 4", 1, 576, 6),
        BUS_OVER(21, "Bus Over", 3, 288, 6),
        BUS_UNDER(22, "Bus Under", 3, 288, 6),
        BUS_SOFT_FAILED(23, "Bus Soft Failed", 1, 288, 6),
        VOLTAGE_LOW(24, "Voltage Low", 1, 288, 6),
        VOLTAGE_HIGH(25, "Voltage High", 1, 288, 6),
        BATTERY_VOLTAGE_LOW(26, "Battery Voltage Low", 3, 0, 0),
        BATTERY_VOLTAGE_HIGH(27, "Battery Voltage High", 3, 0, 0),
        BATTERY_LOW_HYBRID(28, "Battery Low in Hybrid Mode", 2, 0, 0),
        BATTERY_UNDER(29, "Battery Under", 2, 0, 0),
        BATTERY_DERATING_2(30, "Battery Derating", 2, 0, 0),
        BATTERY_EQUALIZATION(31, "Battery equalization", 1, 0, 0),

        // W2范围告警 (32-51)
        BATTERY_WEAK(32, "Battery Weak", 1, 0, 0),
        FAN_LOCKED_2(33, "Fan Locked", 1, 48, 6),
        OVER_CURRENT(34, "Over Current", 3, 288, 6),
        SOFT_FAILED(35, "Soft Failed", 2, 1, 240),
        SELF_TEST_FAILED(36, "Self Test Failed", 1, 1, 240),
        OP_DC_VOLTAGE_OVER(37, "OP DC Voltage Over", 3, 0, 0),
        CURRENT_SENSOR_FAIL(38, "Current Sensor Fail", 1, 576, 6),
        GRID_VOLTAGE_HIGH_LOSS(39, "Grid Voltage High Loss", 1, 576, 6),
        GRID_VOLTAGE_LOW_LOSS(40, "Grid Voltage Low Loss", 1, 576, 6),
        GRID_FREQUENCY_HIGH_LOSS(41, "Grid Frequency High Loss", 1, 576, 6),
        GRID_FREQUENCY_LOW_LOSS(42, "Grid Frequency Low Loss", 1, 576, 6),
        GRID_VOLTAGE_INPUT_LOSS(43, "Grid Voltage Input Loss", 1, 576, 6),
        GRID_FREQUENCY_INPUT_LOSS(44, "Grid Frequency Input Loss", 1, 576, 6),
        GRID_VOLTAGE_AVERAGE_OVER(45, "Grid Voltage Average Over", 1, 576, 6),
        GRID_INPUT_ISLAND(46, "Grid Input Island", 2, 1, 240),
        GRID_INPUT_PHASE_DISLOCATION(47, "Grid Input Phase Dislocation", 1, 1, 240),
        EPO_ACTIVE(48, "EPO Active", 3, 1, 240),
        GRID_INPUT_WAVE_LOSS(49, "Grid Input Wave Loss", 2, 3, 241),
        RAPID_SHUTDOWN(50, "rapid shutdown", 2, 288, 6),
        INVERTER_OUTPUT_DISABLED(51, "The inverter output is not enabled in battery mode", 2, 1, 240);

        private final int code;
        private final String description;
        private final int grade;
        private final int alarmCount;
        private final int expireTime;

        AlarmEnum(int code, String description, int grade, int alarmCount, int expireTime) {
            this.code = code;
            this.description = description;
            this.grade = grade;
            this.alarmCount = alarmCount;
            this.expireTime = expireTime;
        }

        public int getCode() {
            return code;
        }

        public String getDescription() {
            return description;
        }

        public int getGrade() {
            return grade;
        }

        public int getAlarmCount() {
            return alarmCount;
        }

        public int getExpireTime() {
            return expireTime;
        }

        private static final Map<Integer, AlarmEnum> CODE_MAP = new ConcurrentHashMap<>();

        static {
            for (AlarmEnum type : values()) {
                CODE_MAP.put(type.code, type);
            }
        }

        public static AlarmEnum fromCode(int code) {
            return CODE_MAP.get(code);
        }
    }

    /**
     * 解析告警字
     * @param wValue 告警字值
     * @param startCode 起始告警码
     * @return 告警列表
     */
    private static List<Alarm> parseW(int wValue, int startCode) {
        return ALARM_CACHE.computeIfAbsent(wValue, k -> {
            List<Alarm> alarms = new ArrayList<>();
            for (int bit = 0; bit < BITS_PER_WORD; bit++) {
                if (((wValue >> bit) & 0x01) == 1) {
                    int alarmCode = startCode + bit;
                    AlarmEnum alarmEnum = AlarmEnum.fromCode(alarmCode);
                    if (alarmEnum != null) {
                        alarms.add(new Alarm(
                                alarmEnum.getCode(),
                                alarmEnum.getDescription(),
                                alarmEnum.getGrade(),
                                alarmEnum.getAlarmCount(),
                                alarmEnum.getExpireTime()
                        ));
                    }
                }
            }
            return alarms;
        });
    }

    /**
     * 解析W1告警字 (0-31)
     */
    public static List<Alarm> parseW1(int w1Value) {
        return parseW(w1Value, 0);
    }

    /**
     * 解析W2告警字 (32-51)
     */
    public static List<Alarm> parseW2(int w2Value) {
        return parseW(w2Value, 32);
    }

    // 解析W3（64~95）
    public static List<Alarm> parseW3(int w3Value) {
        return parseW(w3Value, 64);
    }

    // 解析W4（96~127）
    public static List<Alarm> parseW4(int w4Value) {
        return parseW(w4Value, 96);
    }

    /**
     * 创建告警记录
     */
    public void createAlarm(Equipment sn, Integer w1, Integer w2,
                            ISptDevLogService sptDevLogService,
                            WorkOrdersServiceImpl service,
                            RedisCache redisCache,
                            IConfigInfoService configInfoService) {
        List<Alarm> alarms = new ArrayList<>();
        if (w1 != null) {
            alarms.addAll(parseW1(w1));
        }
        if (w2 != null) {
            alarms.addAll(parseW2(w2));
        }
        sptDevLogService.saveDevAlarmW(sn, alarms, service, redisCache, configInfoService);
    }

    /**
     * 创建故障记录
     */
    public void createFault(Equipment equipment, String f1,
                            ISptDevLogService sptDevLogService,
                            WorkOrdersServiceImpl workOrdersService,
                            RedisCache redisUtil,
                            IConfigInfoService configInfoService) {
        Fault fault = FaultParser.parseF1(f1);
        if (fault != null && !StringUtils.isEmpty(fault.getEnglish())) {
            sptDevLogService.saveDevFault(equipment, fault, workOrdersService, redisUtil, configInfoService);
        }
    }
}